#include <mcp/transport/sse_transport.h>
#include <mcp/error.h>
#include <mcp/json/value.h>

#include <iostream>
#include <sstream>
#include <chrono>
#include <memory>
#include <thread>
#include <vector>
#include <map>
#include <queue>
#include <regex>

namespace mcp {
namespace transport {

// SSE client simulation for demonstration
class SseClientSim {
public:
    struct Event {
        std::string id;
        std::string event;
        std::string data;
        int retry_ms = 0;
    };

    bool connect_events(const std::string& url) {
        std::cout << "[SSE] Connecting to events: " << url << std::endl;
        return true;
    }

    bool connect_message_endpoint(const std::string& url) {
        std::cout << "[SSE] Connecting to message endpoint: " << url << std::endl;
        return true;
    }

    void disconnect() {
        std::cout << "[SSE] Disconnecting" << std::endl;
    }

    bool send_message(const std::string& message) {
        std::cout << "[SSE] Sending message: " << message.substr(0, 100) << "..." << std::endl;
        return true;
    }

    bool poll_event(Event& event) {
        // Simulate receiving SSE events
        static int counter = 0;
        if (counter++ % 15 == 0) {
            event.id = std::to_string(counter);
            event.event = "message";
            event.data = "{\"jsonrpc\":\"2.0\",\"method\":\"test\",\"id\":" + std::to_string(counter) + "}";
            event.retry_ms = 3000;
            return true;
        }
        return false;
    }
};

// SseTransport implementation
struct SseTransport::Impl {
    SseConfig config;
    std::atomic<bool> running{false};
    std::atomic<bool> connected{false};
    std::unique_ptr<std::thread> receiver_thread;
    SseClientSim events_client;
    SseClientSim message_client;
    MessageHandler message_handler;
    ErrorHandler error_handler;
    CloseHandler close_handler;
    OpenHandler open_handler;
    mutable std::mutex transport_mutex;
    std::string last_event_id;

    Impl(const SseConfig& cfg) : config(cfg) {}

    void start_receiving();
    void stop_receiving();
    void handle_events();
    std::string format_sse_event(const SseEvent& event);
    SseEvent parse_sse_event(const std::string& raw_event);
};

SseTransport::SseTransport(const SseConfig& config) : impl_(std::make_unique<Impl>(config)) {}

SseTransport::SseTransport(uint16_t port)
    : impl_(std::make_unique<Impl>(SseConfig{.port = port})) {}

SseTransport::~SseTransport() {
    stop();
}

bool SseTransport::start() {
    std::lock_guard<std::mutex> lock(impl_->transport_mutex);

    if (impl_->running) {
        return true;
    }

    // Connect to SSE events endpoint
    if (!impl_->events_client.connect_events(get_events_url())) {
        if (impl_->error_handler) {
            impl_->error_handler(Error::connection_error("Failed to connect to SSE events endpoint"));
        }
        return false;
    }

    // Connect to message endpoint
    if (!impl_->message_client.connect_message_endpoint(get_url())) {
        if (impl_->error_handler) {
            impl_->error_handler(Error::connection_error("Failed to connect to SSE message endpoint"));
        }
        return false;
    }

    impl_->running = true;
    impl_->connected = true;

    // Start the receiver thread
    impl_->receiver_thread = std::make_unique<std::thread>([this]() {
        impl_->start_receiving();
    });

    // Notify open handler
    if (impl_->open_handler) {
        impl_->open_handler();
    }

    return true;
}

void SseTransport::stop() {
    std::lock_guard<std::mutex> lock(impl_->transport_mutex);

    if (!impl_->running) {
        return;
    }

    impl_->running = false;
    impl_->connected = false;

    // Stop the receiver thread
    impl_->stop_receiving();

    // Disconnect from SSE endpoints
    impl_->events_client.disconnect();
    impl_->message_client.disconnect();

    if (impl_->receiver_thread && impl_->receiver_thread->joinable()) {
        impl_->receiver_thread->join();
        impl_->receiver_thread.reset();
    }

    // Notify close handler
    if (impl_->close_handler) {
        impl_->close_handler();
    }
}

bool SseTransport::is_connected() const {
    return impl_->connected;
}

bool SseTransport::send(const json::Value& message) {
    if (!impl_->running || !impl_->connected) {
        return false;
    }

    try {
        std::string serialized = message.serialize();

        // Check message size limit
        if (serialized.size() > impl_->config.max_message_size) {
            if (impl_->error_handler) {
                impl_->error_handler(Error::validation_error("Message too large"));
            }
            return false;
        }

        bool success = impl_->message_client.send_message(serialized);
        if (!success) {
            if (impl_->error_handler) {
                impl_->error_handler(Error::network_error("Failed to send SSE message"));
            }
            return false;
        }

        return true;
    } catch (const std::exception& e) {
        if (impl_->error_handler) {
            impl_->error_handler(Error::serialization_error(e.what()));
        }
        return false;
    }
}

std::coroutine_handle<> SseTransport::send_async(const json::Value& message) {
    // For SSE transport simulation, send_async behaves the same as send
    // In a real implementation, this would use async HTTP client
    send(message);
    return std::noop_coroutine();
}

void SseTransport::set_message_handler(MessageHandler handler) {
    impl_->message_handler = std::move(handler);
}

void SseTransport::set_error_handler(ErrorHandler handler) {
    impl_->error_handler = std::move(handler);
}

void SseTransport::set_close_handler(CloseHandler handler) {
    impl_->close_handler = std::move(handler);
}

void SseTransport::set_open_handler(OpenHandler handler) {
    impl_->open_handler = std::move(handler);
}

std::string SseTransport::get_type() const {
    return "sse";
}

json::Value SseTransport::get_capabilities() const {
    json::Value capabilities = json::Value::object();
    capabilities["type"] = "sse";
    capabilities["supports_async"] = true;
    capabilities["supports_compression"] = false;
    capabilities["cors_enabled"] = impl_->config.enable_cors;
    capabilities["max_message_size"] = static_cast<int64_t>(impl_->config.max_message_size);
    capabilities["retry_interval"] = impl_->config.retry_interval_ms;
    capabilities["supports_last_event_id"] = impl_->config.enable_last_event_id;
    return capabilities;
}

bool SseTransport::send_event(const SseEvent& event) {
    if (!impl_->running || !impl_->connected) {
        return false;
    }

    try {
        std::string formatted_event = impl_->format_sse_event(event);
        // In a real implementation, this would send the event through the SSE connection
        std::cout << "[SSE] Sending event: " << formatted_event.substr(0, 100) << "..." << std::endl;
        return true;
    } catch (const std::exception& e) {
        if (impl_->error_handler) {
            impl_->error_handler(Error::serialization_error(e.what()));
        }
        return false;
    }
}

bool SseTransport::send_message_event(const json::Value& message) {
    SseEvent event;
    event.event = "message";
    event.data = message.serialize();
    return send_event(event);
}

std::string SseTransport::get_url() const {
    std::ostringstream ss;
    ss << "http://" << impl_->config.host << ":" << impl_->config.port << impl_->config.message_path;
    return ss.str();
}

std::string SseTransport::get_events_url() const {
    std::ostringstream ss;
    ss << "http://" << impl_->config.host << ":" << impl_->config.port << impl_->config.events_path;
    return ss.str();
}

uint16_t SseTransport::get_port() const {
    return impl_->config.port;
}

void SseTransport::update_config(const SseConfig& config) {
    std::lock_guard<std::mutex> lock(impl_->transport_mutex);
    impl_->config = config;
}

const SseConfig& SseTransport::get_config() const {
    return impl_->config;
}

void SseTransport::Impl::start_receiving() {
    while (running) {
        try {
            handle_events();
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        } catch (const std::exception& e) {
            if (error_handler) {
                error_handler(Error::network_error(e.what()));
            }
        }
    }
}

void SseTransport::Impl::stop_receiving() {
    // No specific action needed for simulation
    // The loop in start_receiving will exit when running is false
}

void SseTransport::Impl::handle_events() {
    SseClientSim::Event event;

    while (events_client.poll_event(event)) {
        try {
            // Update last event ID if enabled
            if (config.enable_last_event_id && !event.id.empty()) {
                last_event_id = event.id;
            }

            // Parse JSON message from event data
            if (event.event == "message" || event.event.empty()) {
                auto result = json::Value::parse(event.data);
                if (result && message_handler) {
                    message_handler(*result);
                } else if (!result && error_handler) {
                    error_handler(result.error());
                }
            }
        } catch (const std::exception& e) {
            if (error_handler) {
                error_handler(Error::parse_error(e.what()));
            }
        }
    }
}

std::string SseTransport::Impl::format_sse_event(const SseEvent& event) {
    std::ostringstream ss;

    if (!event.id.empty()) {
        ss << "id: " << event.id << "\n";
    }

    if (!event.event.empty()) {
        ss << "event: " << event.event << "\n";
    }

    // Handle multi-line data
    std::istringstream data_stream(event.data);
    std::string line;
    while (std::getline(data_stream, line)) {
        ss << "data: " << line << "\n";
    }

    if (event.retry_ms > 0) {
        ss << "retry: " << event.retry_ms << "\n";
    }

    ss << "\n"; // End of event
    return ss.str();
}

SseEvent SseTransport::Impl::parse_sse_event(const std::string& raw_event) {
    SseEvent event;
    std::istringstream iss(raw_event);
    std::string line;
    std::string current_data;

    while (std::getline(iss, line)) {
        if (line.empty()) {
            // End of event
            if (!current_data.empty()) {
                event.data = current_data;
                current_data.clear();
            }
            continue;
        }

        if (line.substr(0, 3) == "id:") {
            event.id = line.substr(3);
            // Trim whitespace
            event.id.erase(0, event.id.find_first_not_of(" \t"));
            event.id.erase(event.id.find_last_not_of(" \r\n") + 1);
        } else if (line.substr(0, 6) == "event:") {
            event.event = line.substr(6);
            // Trim whitespace
            event.event.erase(0, event.event.find_first_not_of(" \t"));
            event.event.erase(event.event.find_last_not_of(" \r\n") + 1);
        } else if (line.substr(0, 5) == "data:") {
            std::string data_line = line.substr(5);
            // Trim whitespace
            data_line.erase(0, data_line.find_first_not_of(" \t"));
            data_line.erase(data_line.find_last_not_of(" \r\n") + 1);

            if (!current_data.empty()) {
                current_data += "\n";
            }
            current_data += data_line;
        } else if (line.substr(0, 6) == "retry:") {
            std::string retry_str = line.substr(6);
            // Trim whitespace
            retry_str.erase(0, retry_str.find_first_not_of(" \t"));
            retry_str.erase(retry_str.find_last_not_of(" \r\n") + 1);

            try {
                event.retry_ms = std::stoi(retry_str);
            } catch (...) {
                // Ignore invalid retry values
            }
        }
    }

    // Handle any remaining data
    if (!current_data.empty()) {
        event.data = current_data;
    }

    return event;
}

// SseTransportFactory implementation
std::unique_ptr<Transport> SseTransportFactory::create() {
    return std::make_unique<SseTransport>();
}

std::unique_ptr<Transport> SseTransportFactory::create_with_config(const SseConfig& config) {
    return std::make_unique<SseTransport>(config);
}

std::unique_ptr<Transport> SseTransportFactory::create_with_port(uint16_t port) {
    return std::make_unique<SseTransport>(port);
}

std::string SseTransportFactory::get_type() const {
    return "sse";
}

std::vector<std::string> SseTransportFactory::get_supported_schemes() const {
    return {"http", "https"};
}

// Utility functions for SSE transport
std::unique_ptr<SseTransport> create_sse_transport(uint16_t port) {
    return std::make_unique<SseTransport>(port);
}

std::unique_ptr<SseTransport> create_sse_transport_with_config(const SseConfig& config) {
    return std::make_unique<SseTransport>(config);
}

SseConfig create_sse_config(const std::string& host, uint16_t port, const std::string& path) {
    SseConfig config;
    config.host = host;
    config.port = port;
    config.path = path;
    config.events_path = path + "/events";
    config.message_path = path + "/message";
    return config;
}

} // namespace transport
} // namespace mcp